package com.minsheng.epidemic_rep.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.minsheng.epidemic_rep.entity.DatabaseType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class AbstractBatisBaseConfig implements EnvironmentAware {
    private static final Logger log = LoggerFactory.getLogger(AbstractBatisBaseConfig.class);
    private Environment env;

    @Override
    public void setEnvironment(final Environment environment) {
        this.env = environment;
    }

    @Bean
    public DataSource masterDs() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("spring.datasource.master.driver-class-name"));
        props.put("url", env.getProperty("spring.datasource.master.url"));
        props.put("username", env.getProperty("spring.datasource.master.username"));
        props.put("password", env.getProperty("spring.datasource.master.password"));
        this.setCommonJDBCProperties(props);
        DruidDataSource ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(props);
        // List<Filter> filters = new ArrayList<>();
        // filters.add(wallFilter());
        // ds.setProxyFilters(filters);
        return ds;
    }

    /**
     * private WallConfig wallConfig() { WallConfig wconfig = new WallConfig();
     * wconfig.setMultiStatementAllow(true); return wconfig; }
     * <p>
     * private WallFilter wallFilter() { WallFilter wfilter = new WallFilter();
     * wfilter.setConfig(wallConfig()); return wfilter; }
     **/

    @Bean
    public DataSource slave1Ds() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("spring.datasource.slave1.driver-class-name"));
        props.put("url", env.getProperty("spring.datasource.slave1.url"));
        props.put("username", env.getProperty("spring.datasource.slave1.username"));
        props.put("password", env.getProperty("spring.datasource.slave1.password"));
        this.setCommonJDBCProperties(props);
        DruidDataSource ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(props);
        // List<Filter> filters = new ArrayList<>();
        // filters.add(wallFilter());
        // ds.setProxyFilters(filters);
        return ds;
    }

    @Bean
    public DataSource slave2Ds() throws Exception {
        Properties props = new Properties();
        props.put("driverClassName", env.getProperty("spring.datasource.slave2.driver-class-name"));
        props.put("url", env.getProperty("spring.datasource.slave2.url"));
        props.put("username", env.getProperty("spring.datasource.slave2.username"));
        props.put("password", env.getProperty("spring.datasource.slave2.password"));
        this.setCommonJDBCProperties(props);
        DruidDataSource ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(props);
        // List<Filter> filters = new ArrayList<>();
        // filters.add(wallFilter());
        // ds.setProxyFilters(filters);
        return ds;
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier("masterDs") DataSource masterDs,
                                        @Qualifier("slave1Ds") DataSource slave1Ds,
                                        @Qualifier("slave2Ds") DataSource slave2Ds) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.MASTER, masterDs);
        targetDataSources.put(DatabaseType.SLAVE1, slave1Ds);
        targetDataSources.put(DatabaseType.SLAVE2, slave2Ds);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法
        dataSource.setDefaultTargetDataSource(masterDs);// 默认的datasource设置为myTestDbDataSource

        return dataSource;
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactoryBean(DynamicDataSource ds) {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(ds);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:mybatis/mapper/*.xml"));
            return bean.getObject();
        } catch (Exception e) {
            log.error("sqlSessionFactory创建失败！");
            e.printStackTrace();
            throw new RuntimeException();
        }
    }

    @Bean
    public DataSourceTransactionManager transationManager(DynamicDataSource ds) throws Exception {
        return new DataSourceTransactionManager(ds);
    }

    private void setCommonJDBCProperties(Properties props) {
        props.put("initialSize", env.getProperty("spring.datasource.initialSize"));
        props.put("minIdle", env.getProperty("spring.datasource.minIdle"));
        props.put("maxActive", env.getProperty("spring.datasource.maxActive"));
        props.put("maxWait", env.getProperty("spring.datasource.maxWait"));
//        props.put("validationQuery", env.getProperty("spring.datasource.validationQuery"));
        props.put("testOnBorrow", env.getProperty("spring.datasource.testOnBorrow"));
        props.put("testOnReturn", env.getProperty("spring.datasource.testOnReturn"));
        props.put("testWhileIdle", env.getProperty("spring.datasource.testWhileIdle"));
        props.put("timeBetweenEvictionRunsMillis", env.getProperty("spring.datasource.timeBetweenEvictionRunsMillis"));
        props.put("minEvictableIdleTimeMillis", env.getProperty("spring.datasource.minEvictableIdleTimeMillis"));
//        props.put("removeAbandoned", env.getProperty("spring.datasource.removeAbandoned"));
//        props.put("removeAbandonedTimeOut", env.getProperty("spring.datasource.removeAbandonedTimeOut"));
//        props.put("logAbandoned", env.getProperty("spring.datasource.logAbandoned"));
        props.put("poolPreparedStatements", env.getProperty("spring.datasource.poolPreparedStatements"));
        props.put("maxPoolPreparedStatementPerConnectionSize",
                env.getProperty("spring.datasource.maxPoolPreparedStatementPerConnectionSize"));
        props.put("filters", env.getProperty("spring.datasource.filters"));
    }
}